﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace MyServer.Common
{
    /// <summary>
    /// 表示数据读取器基类
    /// </summary>
    public abstract class DataReaderBase
    {

        #region ========私有变量========

        /// <summary>
        /// 线程锁对象
        /// </summary>
        private static object lockobj = new object();
        /// <summary>
        /// 一个标志，用来指示是否应该关闭数据读取器
        /// </summary>
        private bool IsStop = false;

        #endregion

        #region========公有委托========

        /// <summary>
        /// 将要接收数据包的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void BeforeReadEventHandler(object sender, ref DataBeforeTransportEventArgs e);
        /// <summary>
        /// 接收数据包操作完成的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ReadCompeleteEventHandler(object sender, ref DataAfterTransportEventArgs e);
        /// <summary>
        /// 发生错误时的事件委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void ErrorCatchedEventHandler(object sender, ref ErrorCatchedEventArgs e);
        #endregion

        #region==========事件==========

        /// <summary>
        /// 数据读取之前
        /// </summary>
        public event BeforeReadEventHandler BeforeReadData;

        /// <summary>
        /// 数据读取之后
        /// </summary>
        public event ReadCompeleteEventHandler AfterReadData;

        /// <summary>
        /// 发生错误时
        /// </summary>
        public event ErrorCatchedEventHandler ErrorCatched;

        #endregion

        #region ==========属性==========

        /// <summary>
        /// 表示数据读取器监听工具的监听工作实例
        /// </summary>
        public Task ListenMainTask { get; private set; }

        /// <summary>
        /// 表示数据读取器的读取工作实例
        /// </summary>
        public Task ReadMainTask { get; private set; }

        /// <summary>
        /// 获取数据读取器的读取队列
        /// </summary>
        public Queue ReadQueue { get; private set; }

        /// <summary>
        /// 获取当前已读取但未能分组的数据包列表
        /// </summary>
        public ArrayList UnGroupedPkg { get; protected set; }

        /// <summary>
        /// 获取或设置接收器等待队列的速率
        /// </summary>
        public int ListenRate { get; set; }

        /// <summary>
        /// 表示与读取器绑定的数据中心
        /// </summary>
        public DataCenterBase DataCenter { get; private set; }

        /// <summary>
        /// 获取正在接收的客户端信息列表
        /// 类型：<see cref="MyServer.Common.RecivingConnectInfo"/>
        /// </summary>
        public ArrayList RecivingConnectList { get; private set; }

        #endregion

        #region ========私有函数========

        /// <summary>
        /// 私有侦听函数
        /// </summary>
        protected virtual void DoListen()
        {
            lock (lockobj)
            {
                while (ReadQueue.Count == 0 && IsStop == false)
                {
                    System.Threading.Thread.Sleep(ListenRate);
                }

                if (IsStop)
                    return;

                if (ReadMainTask.Status != TaskStatus.Running)
                {
                    ReadMainTask.Start();
                }

                this.ListenMainTask = new Task(DoListen);

            }
        }

        /// <summary>
        /// 私有读取函数
        /// </summary>
        protected virtual void DoRead()
        {
            lock (lockobj)
            {
                while (ReadQueue.Count > 0 && IsStop == false)
                {
                    DataPackageCollection pkg = (DataPackageCollection)ReadQueue.Dequeue();
                    RemoveConnect(pkg.Tag);
                    DataBeforeTransportEventArgs e = new DataBeforeTransportEventArgs(pkg);
                    DataAfterTransportEventArgs e1 = new DataAfterTransportEventArgs(pkg);
                    pkg.IsRecive = true;

                    //校验未分组的数据包
                    lock (UnGroupedPkg)
                    {
                        foreach (DataPackage ugppkg in UnGroupedPkg.ToArray())
                        {
                            if (ugppkg.Tag == pkg.Tag && ugppkg.PackageName == pkg.PackageName)
                            {
                                pkg.Add(ugppkg);
                                pkg.OperatedPkgCount++;
                                UnGroupedPkg.Remove(ugppkg);
                                if (pkg.OperatedPkgCount == pkg.Count)
                                {
                                    pkg.State = PackageCollectionState.ReciveCompelete;
                                    break;
                                }
                            }
                        }
                    }

                    if (pkg.PrecedenceLeft - 1 <= 0 || pkg.PrecedenceLeft > pkg.Precedence)//判定优先级
                    {
                        if (BeforeReadData != null)
                            BeforeReadData(this, ref e);
                        if (!e.Canceled)
                        {
                            bool IsSucceed = false;
                            try
                            {
                                IsSucceed = Read(ref pkg);
                            }
                            catch (Exception ex)
                            {
                                ErrorCatchedEventArgs e2 = new ErrorCatchedEventArgs(ex, pkg);
                                e2.Operate = ErrorOperate.RemoveCol;
                                if (ErrorCatched != null)
                                {
                                    ErrorCatched(this, ref e2);
                                }
                                switch (e2.Operate)
                                {
                                    case ErrorOperate.RemoveCol:
                                        continue;
                                    case ErrorOperate.StopSend:
                                        return;
                                    case ErrorOperate.Pass:
                                        break;
                                    case ErrorOperate.ClearQueue:
                                        ReadQueue.Clear();
                                        break;
                                }
                                IsSucceed = false;
                            }
                            e1.IsSucceed = IsSucceed;
                        }
                        else
                        {
                            e1.IsSucceed = false;
                        }
                        e1.Canceled = e.Canceled;
                        pkg.PrecedenceLeft = pkg.Precedence;

                        if (!e.Canceled)
                        {
                            //终结点判定
                            if ((pkg.OperatedPkgCount < pkg.Count && pkg.State == PackageCollectionState.Reciving) && e1.IsSucceed != false)//正在处理
                            {
                                ReadQueue.Enqueue(pkg);
                                AddConnect(pkg.Tag);
                            }
                            if (pkg.State == PackageCollectionState.ReadyForRecive)//准备接收
                            {
                                pkg.State = PackageCollectionState.Reciving;
                            }
                            else if (pkg.OperatedPkgCount == pkg.Count)//接收完毕
                            {
                                pkg.State = PackageCollectionState.ReciveCompelete;
                            }
                            else if (pkg.OperatedPkgCount > pkg.Count)//接收不规范
                            {
                                pkg.State = PackageCollectionState.ErrorRead;
                            }
                        }

                        if (AfterReadData != null)
                            AfterReadData(this, ref e1);
                    }
                    else
                    {
                        pkg.PrecedenceLeft--;
                    }
                }
                this.UnGroupedPkg.Clear();
                this.ReadMainTask = new Task(DoRead);
                if (ListenMainTask.Status != TaskStatus.Running)
                    ListenMainTask.Start();

            }
        }
        /// <summary>
        /// 加入链接
        /// </summary>
        /// <param name="tag"></param>
        private void AddConnect(object tag)
        {
            lock(RecivingConnectList)
            {
                foreach(RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if(i.Tag==tag)
                    {
                        i.RecivingCount++;
                        return;
                    }
                }
                RecivingConnectInfo info = new RecivingConnectInfo(tag);
                RecivingConnectList.Add(info);
            }
        }
        /// <summary>
        /// 移除链接
        /// </summary>
        /// <param name="tag"></param>
        private void RemoveConnect(object tag)
        {
            lock(RecivingConnectList)
            {
                foreach(RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if(i.Tag==tag)
                    {
                        if(i.RecivingCount==1)
                        {
                            RecivingConnectList.Remove(i);
                        }
                        else
                        {
                            i.RecivingCount--;
                        }
                        return;
                    }
                }
            }
        }
 
        #endregion

        #region========公用方法========

        /// <summary>
        /// 开始监听接收队列
        /// </summary>
        public virtual void StartListen()
        {
            IsStop = false;
            if (ListenMainTask.Status != TaskStatus.Running)
            {
                ListenMainTask = new Task(DoListen);
                ListenMainTask.Start();
            }
        }

        /// <summary>
        /// 停止数据读取器
        /// </summary>
        public virtual void Stop()
        {
            this.IsStop = true;
            while (ReadMainTask.Status == TaskStatus.Running || ListenMainTask.Status == TaskStatus.Running)
            {
                System.Threading.Thread.Sleep(10);
            }
        }
        /// <summary>
        /// 获取拥有指定Tag数据的数据包的剩余数量
        /// </summary>
        /// <param name="tag"></param>
        /// <returns>若没有数据则返回-1,否则返回数量</returns>
        public virtual int GetTagLeftPacket(object tag)
        {
            lock(RecivingConnectList)
            {
                foreach(RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if(i.Tag==tag)
                    {
                        return i.RecivingCount;
                    }
                }
                return -1;
            }
        }

        #endregion

        #region========抽象函数========

        /// <summary>
        /// 开始尝试读取指定包中的数据
        /// </summary>
        /// <param name="pkg">要读取的数据包列表</param>
        /// <returns>是否成功完成一次操作</returns>
        protected virtual bool Read(ref DataPackageCollection pkg)
        {
            lock (lockobj)
            {
                try
                {
                    if (pkg.State == PackageCollectionState.ReciveCompelete)
                        return true;

                    //取得数据包内包含的流信息
                    Stream stream = GetStream(pkg.Tag);
                    lock(stream)
                    {
                    if (GetDataAvilable(pkg.Tag) <= 0)
                    {
                        pkg.State = PackageCollectionState.Reciving;
                        return true;
                    }

                    BinaryReader br = new BinaryReader(stream);

                    bool ispkgcol = br.ReadBoolean();//读取当前数据块是否为新的数据包列表

                    int dataLen = br.ReadInt32();//取得数据长度

                    byte[] dataBuffer = br.ReadBytes(dataLen);

                    if (!ispkgcol)//数据类型为数据包
                    {
                        DataPackage rpkg = DataPackage.FromByte(dataBuffer);

                        if (rpkg.PackageName != pkg.PackageName)//当前接收的数据包不属于当前数据包集合
                        {
                            pkg.State = PackageCollectionState.Reciving;
                            rpkg.Tag = pkg.Tag;//将当前连接绑定到数据包
                            UnGroupedPkg.Add(rpkg);//将数据包加入至未分组数据包列表中
                            return true;
                        }
                        else//当前接收的数据包属于当前数据包集合
                        {
                            pkg.Add(rpkg);//将数据包加入数据包集合中
                            pkg.OperatedPkgCount++;
                            if (pkg.OperatedPkgCount == pkg.Count)
                                pkg.State = PackageCollectionState.ReciveCompelete;
                            return true;
                        }
                    }
                    else//数据类型为数据包列表
                    {

                        DataPackageCollection npkg;

                        if (pkg.State == PackageCollectionState.Created)
                        {
                            npkg = pkg;
                        }
                        else
                        {
                            npkg = new DataPackageCollection("", PackageCollectionType.ForRecive);
                            npkg.Tag = pkg.Tag;
                            pkg.State = PackageCollectionState.Reciving;
                        }

                        npkg.InitFromByte(dataBuffer);//读取数据包列表

                        if (npkg.State != PackageCollectionState.Inited)
                            return false;

                        npkg.State = PackageCollectionState.ReadyForRecive;
                        bool isExist = false;

                        lock (ReadQueue)
                        {
                            foreach (DataPackageCollection p in ReadQueue.ToArray())
                            {
                                if (p.PackageName == npkg.PackageName)//数据包列表已存在在队列中
                                {
                                    //清除数据包列表中的数据包，准备重新接收数据包
                                    p.Clear();
                                    p.OperatedPkgCount = 0;
                                    p.State = PackageCollectionState.Reciving;
                                    isExist = true;
                                    break;
                                }
                            }
                        }
                        if (!isExist)//当数据包列表不在队列中时
                        {
                            ReadQueue.Enqueue(npkg);//将数据包列表加入接收队列中
                            AddConnect(npkg.Tag);
                        }
                        return true;
                    }
                        }
                }
                catch (Exception ex)
                {
#if DEBUG
                    throw (ex);
#else
                    return false;
#endif
                }

            }
        }
        /// <summary>
        /// 根据数据包的Tag标签获取读取数据包的流
        /// </summary>
        /// <param name="Tag">Tag标签</param>
        /// <returns>获取到的流</returns>
        protected abstract Stream GetStream(object Tag);
        /// <summary>
        /// 获取数据包Tag流中可供读取的数据数
        /// </summary>
        /// <param name="Tag"></param>
        /// <returns></returns>
        protected abstract int GetDataAvilable(object Tag);
        #endregion

        #region========构造函数========

        public DataReaderBase(DataCenterBase Center)
        {
            //初始化工作流
            this.ReadMainTask = new Task(DoRead);
            this.ListenMainTask = new Task(DoListen);
            
            //初始化列表
            this.ReadQueue = Queue.Synchronized(new Queue());
            this.UnGroupedPkg = ArrayList.Synchronized(new ArrayList());
            this.RecivingConnectList = ArrayList.Synchronized(new ArrayList());

            //初始化设定
            this.ListenRate = 10;
            this.DataCenter = Center;
        }

        #endregion


    }

}
